from qturboframe.lib.utils.by import By
from qturboframe.lib.report.log import logger
from qturboframe.lib.webdriver.exceptions import SeleniumError
from qturboframe.lib.webdriver.remote.webelement import WebElement
from qturboframe.lib.utils.CustomError.custom_error import CustomError
from qturboframe.public_ui.__common__ import deal_form_data
from qturboframe.public_ui.base_element import BaseElement
from qturboframe.public_ui.h_ui.input_type import InputType
from qturboframe.public_ui.h_ui.input_number import InputNumber
from qturboframe.public_ui.h_ui.type_field import TypeField
from qturboframe.public_ui.h_ui.textarea import TextArea
from qturboframe.public_ui.h_ui.select import Select
from qturboframe.public_ui.h_ui.select_tree import SelectTree
from qturboframe.public_ui.h_ui.select_table import SelectTable
from qturboframe.public_ui.h_ui.calendar import Calendar
from qturboframe.public_ui.h_ui.timer import Timer
from qturboframe.public_ui.h_ui.transfer import Transfer
from qturboframe.public_ui.h_ui.radio import Radio
from qturboframe.public_ui.h_ui.checkbox import Checkbox


class Form(BaseElement):
    '''
    hui的表单操作

    :Attributes:
     - _control_div: 控件所在特定div元素，webelement对象
     - _elements: 控件元素webelement对象，对于控件组或者则定义为webelement对象列表
    '''

    __RADIO_CLASS = r'h-radio-group'
    __CHECKBOX_CLASS = r'h-checkbox-group'
    __SELECT_SINGLE_CLASS = r'h-select-single'
    __SELECT_MULTIPLE_CLASS = r'h-select-multiple'
    __SELECT_TREE_SINGLE_CLASS = r'h-selectTree-single'
    __SELECT_TREE_MULTIPLE_CLASS = r'h-selectTree-multiple'
    __SELECT_TABLE_SINGLE_CLASS = r'h-selectTable-single'
    __TYPE_FIELD_CLASS = r'h-typefield'
    __INPUT_TYPE_CLASS = r'h-input-wrapper'
    __INPUT_NUMBER_CLASS = r'h-input-number'
    __CALENDAR_CLASS = r'h-date-picker'
    __GROUP_CLASS = r'h-row'

    _control_div = WebElement
    _elements = WebElement

    def __init__(self, element_para, father=None, timeout=5, index=1):
        if isinstance(element_para, dict) and By.TEXT in list(element_para.keys())[0]:
            text = element_para.get(By.TEXT)
            xpath = ".//*[contains(text(),'{}')]//ancestor::form[1]".format(text)
            temps = father.find_elements_by_attribute(By.XPATH,xpath, timeout=timeout)
            displayed_forms = []
            if len(temps)>0:
                for temp in temps:
                    if temp.is_displayed and temp.text!='':
                        displayed_forms.append(temp)
            else:
                message = "没有找到xpath为：{} 的form".format(xpath)
                raise SeleniumError(CustomError.Error_EQ03001000_Cannot_Find_Element, message)
            super().__init__(displayed_forms[index-1], timeout=timeout)
        else:
            super().__init__(element_para, father, timeout)

    def auto_fill(self, inputdata):
        '''
        hui表单自动填充功能

        :Args:
         - inputdata: 输入数据，需要定位的表单抬头和待输入文本

        :Raises:
            SeleniumError: 表单填充或校验出错

        :Example:
         - 例: form.auto_fill({'姓名':'admin','年龄':'25','工号':'asdf1234'})
        '''
        logger.info("表单填写开始")
        try:
            for input_key, input_value in inputdata.items():
                if input_value == '-':
                    continue
                key, value, flag, label_seq = deal_form_data(input_key, input_value)

                label_elements = self.element.find_elements_by_attribute(
                    'class name', 'h-form-item-label', 'text:' + key,
                    timeout=self.timeout)
                if len(label_elements) == 0:
                    message = "没有找到“{}”控件".format(key)
                    raise SeleniumError(CustomError.Error_EQ03001000_Cannot_Find_Element, message)
                label = label_elements[label_seq - 1]

                self._control_div = label.find_element_by_attribute(
                    'xpath', './following-sibling::div[@class=\'h-form-item-content\']/'
                             'div[not(contains(@style, "display: none;"))]',
                    timeout=self.timeout)
                # 确定类型
                control_type_list = self.__confirm_type()
                if len(control_type_list) > 1:
                    templist = list()
                    for i in range(0, len(control_type_list)):
                        templist.append([value[i]])
                    value = templist
                elif len(control_type_list) == 0:
                    continue
                else:
                    value = [value]
                # 识别控件并执行
                for i, control_type in enumerate(control_type_list):
                    # 根据控件类型选择控件操作
                    if control_type == self.__INPUT_TYPE_CLASS:
                        self.__deal_input_type(key, value[i], flag)
                    elif control_type == self.__INPUT_NUMBER_CLASS:
                        self.__deal_input_number(key, value[i], flag)
                    elif control_type == self.__TYPE_FIELD_CLASS:
                        self.__deal_type_field(key, value[i], flag)
                    elif control_type == self.__SELECT_SINGLE_CLASS:
                        self.__deal_select_single(key, value[i], flag)
                    elif control_type == self.__SELECT_MULTIPLE_CLASS:
                        self.__deal_select_multiple(key, value[i], flag)
                    elif control_type == self.__SELECT_TREE_SINGLE_CLASS:
                        self.__deal_select_tree_single(key, value[i], flag)
                    elif control_type == self.__SELECT_TREE_MULTIPLE_CLASS:
                        self.__deal_select_tree_multiple(key, value[i], flag)
                    elif control_type == self.__SELECT_TABLE_SINGLE_CLASS:
                        self.__deal_select_table_single(key, value[i], flag)
                    elif control_type == self.__RADIO_CLASS:
                        self.__deal_radio(key, value[i], flag)
                    elif control_type == self.__CHECKBOX_CLASS:
                        self.__deal_checkbox(key, value[i], flag)
                    elif control_type == self.__CALENDAR_CLASS:
                        i_icon = self._elements.find_element_by_attribute(
                            'css selector', 'div.h-date-picker-rel i.h-icon', timeout=self.timeout)
                        icon_class_list = i_icon.get_attribute('class').split(' ')
                        if 'h-icon-time' in icon_class_list:
                            self.__deal_timer(key, value[i], flag)
                        elif 'h-icon-activity' in icon_class_list:
                            self.__deal_calendar(key, value[i], flag)
        except Exception as msg:
            raise SeleniumError(msg)
        logger.info("表单填写结束")

    def __confirm_type(self):
        # 获取控件层div的class属性
        div_class_list = self._control_div.get_attribute('class').split(' ')
        # 判定控件类型
        if self.__INPUT_TYPE_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__INPUT_TYPE_CLASS]
        elif self.__INPUT_NUMBER_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__INPUT_NUMBER_CLASS]
        elif self.__TYPE_FIELD_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__TYPE_FIELD_CLASS]
        elif self.__SELECT_SINGLE_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__SELECT_SINGLE_CLASS]
        elif self.__SELECT_MULTIPLE_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__SELECT_MULTIPLE_CLASS]
        elif self.__SELECT_TREE_SINGLE_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__SELECT_TREE_SINGLE_CLASS]
        elif self.__SELECT_TREE_MULTIPLE_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__SELECT_TREE_MULTIPLE_CLASS]
        elif self.__SELECT_TABLE_SINGLE_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__SELECT_TABLE_SINGLE_CLASS]
        elif self.__CALENDAR_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__CALENDAR_CLASS]
        elif self.__RADIO_CLASS in div_class_list:
            self._elements = self._control_div.find_elements_by_attribute(
                'tag name', 'input', timeout=self.timeout)
            return [self.__RADIO_CLASS]
        elif self.__CHECKBOX_CLASS in div_class_list:
            self._elements = self._control_div.find_elements_by_attribute(
                'tag name', 'input', timeout=self.timeout)
            return [self.__CHECKBOX_CLASS]
        elif self.__GROUP_CLASS in div_class_list:
            templist = list()
            sub_divs = self._control_div.find_elements_by_attribute(
                'xpath', './div/div', timeout=self.timeout)
            for i in range(0, len(sub_divs)):
                self._control_div = sub_divs[i]
                templist.extend(self.__confirm_type())
            return templist
        else:
            logger.warn('非表单控件')
            return []

    def __deal_input_type(self, key, value, flag=''):
        '''
        处理hui文本框

        :Args:
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        input_type = InputType(self._elements, timeout=self.timeout)
        text = value[0]
        if flag == '':
            logger.info(key + '进行文本框填充，填充内容为:' + text)
            input_type.set_value(text)
            return
        else:
            if 'R' in flag:
                if input_type.is_readonly():
                    logger.info(key + '只读检查通过。')
                else:
                    message = key + '只读检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'D' in flag:
                if input_type.is_default(text):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'M' in flag:
                if input_type.is_nonnull():
                    logger.info(key + '必填项校验通过。')
                    input_type.set_value(text)
                else:
                    message = key + '必填项校验未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)

    def __deal_input_number(self, key, value, flag=''):
        '''
        处理hui数字框

        :Args:
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        input_number = InputNumber(self._elements, timeout=self.timeout)
        text = value[0]
        if flag == '':
            logger.info(key + '进行数字框填充，填充内容为:' + text)
            input_number.set_value(text)
            return
        else:
            if 'R' in flag:
                if input_number.is_readonly():
                    logger.info(key + '只读检查通过。')
                else:
                    message = key + '只读检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'D' in flag:
                if input_number.is_default(text):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'M' in flag:
                if input_number.is_nonnull():
                    logger.info(key + '必填项校验通过。')
                    input_number.set_value(text)
                else:
                    message = key + '必填项校验未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)

    def __deal_type_field(self, key, value, flag=''):
        '''
        处理hui金额框

        :Args:
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        type_field = TypeField(self._elements, timeout=self.timeout)
        text = value[0]
        if flag == '':
            logger.info(key + '进行文本框填充。')
            type_field.set_value(text)
        else:
            if 'R' in flag:
                if type_field.is_readonly():
                    logger.info(key + '只读检查通过。')
                else:
                    message = key + '只读检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'D' in flag:
                if type_field.is_default(text):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'M' in flag:
                if type_field.is_nonnull():
                    logger.info(key + '必填项校验通过。')
                    type_field.set_value(text)
                else:
                    message = key + '必填项校验未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)

    def __deal_textarea(self, key, value, flag=''):
        '''
        处理hui多行文本框

        :Args:
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        textarea = TextArea(self._elements, timeout=self.timeout)
        text = value[0]
        if flag == '':
            logger.info(key + '进行文本框填充。')
            textarea.set_value(text)
            return
        else:
            if 'R' in flag:
                if textarea.is_readonly():
                    logger.info(key + '只读检查通过。')
                else:
                    message = key + '只读检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'D' in flag:
                if textarea.is_default(text):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'M' in flag:
                if textarea.is_nonnull():
                    logger.info(key + '必填项校验通过。')
                    textarea.set_value(text)
                else:
                    message = key + '必填项校验未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)

    def __deal_radio(self, key, value, flag=''):
        '''
        处理hui单选按钮

        :Args:
         - key: 控件名称
         - value: 选择项
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 选择或判断值是出错
        '''
        radio = Radio(self._elements, timeout=self.timeout)
        text = value[0]
        if flag == '':
            logger.info(key + '进行单选按钮选择。')
            radio.set_value(text)
        else:
            if 'D' in flag:
                if radio.is_default(text):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)

    def __deal_checkbox(self, key, value, flag=''):
        '''
        处理hui复选按钮

        :Args:
         - key: 控件名称
         - value: 选择项
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 选择或判断值是出错
        '''
        checkbox = Checkbox(self._elements, timeout=self.timeout)
        text = value
        if flag == '':
            logger.info(key + '进行复选框按钮选择。')
            checkbox.set_value(text)
        else:
            if 'D' in flag:
                if checkbox.is_default(text):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)

    def __deal_select_single(self, key, value, flag=''):
        '''
        处理hui单选下拉框

        :Args:
         - key: 控件名称
         - value: 下拉选项，list类型
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 选择或判断值是出错
        '''
        select = Select(self._elements, timeout=self.timeout)
        text = value[0]
        if flag == '':
            logger.info(key + '进行单选下拉框选择。')
            select.set_value_for_single(text, self.timeout)
        else:
            if 'D' in flag:
                if select.is_default_for_single(value[0]):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'M' in flag:
                if select.is_nonnull():
                    logger.info(key + '必填项校验通过。')
                    select.set_value_for_single(text, self.timeout)
                else:
                    message = key + '必填项校验未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)

    def __deal_select_multiple(self, key, value, flag=''):
        '''
        处理hui多选下拉框

        :Args:
         - key: 控件名称
         - value: 下拉选项，list类型
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 选择或判断值是出错
        '''
        select = Select(self._elements, timeout=self.timeout)
        if flag == '':
            logger.info(key + '进行复选下拉框选择。')
            select.set_value_for_multiple(value)
        else:
            if 'D' in flag:
                if select.is_default_for_multiple(value):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'M' in flag:
                if select.is_nonnull():
                    logger.info(key + '必填项校验通过。')
                    select.set_value_for_multiple(value)
                else:
                    message = key + '必填项校验未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)

    def __deal_select_tree_single(self, key, value, flag=''):
        '''
        处理hui单选下拉框

        :Args:
         - key: 控件名称
         - value: 下拉选项，list类型
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 选择或判断值是出错
        '''
        select_tree = SelectTree(self._elements, timeout=self.timeout)
        if flag == '':
            logger.info(key + '进行单选树形下拉框选择。')
            select_tree.set_value_for_single(value[0], self.timeout)
        else:
            if 'D' in flag:
                if select_tree.is_default(value[0]):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'M' in flag:
                if select_tree.is_nonnull():
                    logger.info(key + '必填项校验通过。')
                    select_tree.set_value_for_single(value[0], self.timeout)
                else:
                    message = key + '必填项校验未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)

    def __deal_select_tree_multiple(self, key, value, flag=''):
        '''
        处理hui多选下拉框

        :Args:
         - key: 控件名称
         - value: 下拉选项，list类型
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 选择或判断值是出错
        '''
        select_tree = SelectTree(self._elements, timeout=self.timeout)
        if flag == '':
            logger.info(key + '进行复选树形下拉框选择。')
            select_tree.set_value_for_multiple(value)
        else:
            if 'D' in flag:
                if select_tree.is_default(','.join(value)):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'M' in flag:
                if select_tree.is_nonnull():
                    logger.info(key + '必填项校验通过。')
                    select_tree.set_value_for_multiple(value)
                else:
                    message = key + '必填项校验未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)

    def __deal_select_table_single(self, key, value, flag=''):
        '''
        处理hui单选下拉表格框

        :Args:
         - key: 控件名称
         - value: 下拉选项，list类型
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 选择或判断值是出错
        '''
        select_table = SelectTable(self._elements, timeout=self.timeout)
        if flag == '':
            logger.info(key + '进行复选树形下拉框选择。')
            select_table.set_value_for_single(value[0], self.timeout)
        else:
            if 'D' in flag:
                if select_table.is_default_for_single(value[0]):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'M' in flag:
                if select_table.is_nonnull():
                    logger.info(key + '必填项校验通过。')
                    select_table.set_value_for_single(value[0], self.timeout)
                else:
                    message = key + '必填项校验未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)

    def __deal_calendar(self, key, value, flag=''):
        '''
        处理hui日历下拉框

        :Args:
         - key: 控件名称
         - value: 下拉选项，list类型
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 选择或判断值是出错
        '''
        calendar = Calendar(self._elements, timeout=self.timeout)
        if flag == '':
            logger.info(key + '进行日期选择。')
            calendar.set_value(value[0])
        else:
            if 'D' in flag:
                if calendar.is_default(value[0]):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'M' in flag:
                if calendar.is_nonnull():
                    logger.info(key + '必填项校验通过。')
                    calendar.set_value(value[0])
                else:
                    message = key + '必填项校验未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)

    def __deal_timer(self, key, value, flag=''):
        '''
        处理hui时间下拉框

        :Args:
         - key: 控件名称
         - value: 下拉选项，list类型
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 选择或判断值是出错
        '''
        timer = Timer(self._elements, timeout=self.timeout)
        if flag == '':
            logger.info(key + '进行时间选择。')
            timer.set_value(value[0])
        else:
            if 'D' in flag:
                if timer.is_default(value[0]):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)
            if 'M' in flag:
                if timer.is_nonnull():
                    logger.info(key + '必填项校验通过。')
                    timer.set_value(value[0])
                else:
                    message = key + '必填项校验未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)

    def __deal_transfer(self, key, value, flag=''):
        '''
        处理hui穿梭框

        :Args:
         - key: 控件名称
         - value: 穿梭框选项，list类型
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 选择或判断值是出错
        '''
        transfer = Transfer(self._elements, timeout=self.timeout)
        if flag == '':
            logger.info(key + '进行穿梭框值选择。')
            transfer.set_value_for_multiple(value)
        else:
            if 'D' in flag:
                if transfer.is_default(value):
                    logger.info(key + '默认值检查通过。')
                else:
                    message = key + '默认值检查未通过。'
                    raise SeleniumError(CustomError.Error_EQ03009000_Form_Check, message)



